Build the app
We're going to install the Storage app's dependencies, build the app, and then explain what Cubist does behind the scenes during the build process.
Install app dependencies
The following instructions assume that you have installed Cubist.
Let's start by installing the Cubist Node.js SDK and related dependencies.
cd
to the application directory of
your chosen example and language. Then:
- npm
- yarn
npm install
yarn
Build instructions
In the cubist-config.json
we specify the target
chains
on which each contract should run:
{
...
"targets": {
"ethereum" : {
"files": ["./contracts/StorageReceiver.sol"]
},
"polygon": {
"files": ["./contracts/StorageSender.sol"]
}
},
...
}
To change chains, simply alter the configuration file to specify a different chain.
Cubist only allows you to assign chains at a per file granularity---not per contract. If you have two contracts in the same file and want to deploy them on different chains, you'll have to put each contract in its own file.
Now that we've specified where our contracts should run, we build the project using Cubist:
- JavaScript
- TypeScript
cubist build
- npm
- yarn
cubist build && npm run build
cubist build && yarn build
What's going on behind the scenes
When you invoke build
, Cubist generates new files in the build
directory, organized with one directory per target chain:
build
├── ethereum
│ ├── artifacts // Compiled contracts that will run on ethereum
│ │ ├── ...
│ └── contracts // Source files of original and shim contracts on ethereum
| └── ...
├── orm
│ └── index.js/.ts // ORM interface we'll use in the app to interface with contracts
└── polygon
├── artifacts // Compiled contracts that will run on polygon
│ ├── StorageReceiver.sol
│ │ └── StorageReceiver.json // ABI (and more) for the shim StorageReceiver contract
│ └── StorageSender.sol
│ └── StorageSender.json // ABI (and more) for the "normal" StorageSender contract
└── contracts
├── StorageReceiver.bridge.json // Configuration for the Cubist relayer
├── StorageReceiver.sol // Shim contract source
└── StorageSender.sol // Original StorageSender source
Within each target directory---here, the polygon
and ethereum
directories---Cubist
saves:
- the ABIs produced when compiling the contracts with
solc
(within theartifacts
directory) - the original and shim source files (in the
contracts
directory).
In this example, the interesting files are in the
polygon
directory. That's because the StorageSender
contract, deployed on
Polygon, makes a cross-chain call by executing receiver.store(..)
on a
StorageReceiver
contract deployed on Ethereum.
As a result, Cubist must generate a StorageReceiver
shim on Polygon for the
the StorageSender
contract to interact with; that shim will emit events anytime
StorageSender
calls a StorageReceiver
function, and the off-chain Cubist relayer
will relay those events to the real StorageReceiver
contract on Ethereum. Here's
an example of the generated shim code, which lives in
build/polygon/contracts/StorageReceiver.sol
:
contract StorageReceiver {
event __cubist_event_StorageReceiver_store(uint256 num);
...
function store(uint256 num) public onlyCaller {
emit __cubist_event_StorageReceiver_store(num);
}
}
The build also generates the information that lets the off-chain relayer do its
job; this information is in the StorageReceiver.bridge.json
file.
You should not modify any of the files in the build
directory.
These files are automatically generated, so your changes may get
overwritten.
The build/orm
directory
Finally, the orm
directory contains Cubist-generated bindings to
our smart contracts. We'll use the bindings to interface with our
contracts from JavaScript in the next section.